package com.cola.colaboot.utils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.cola.colaboot.config.exception.ColaException;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;

import java.security.Key;
import java.util.Date;

/**
 *  多设备登录：token作为key，用户信息作为value
 *  单设备登录解决方案：
 *      用户登录成功后保存token(作为key)到redis，并设置redis过期时间，同时保存list类型-用户名作为item-token作为value到redis
 *      请求时验证token是否在redis中还存在-使用get(key)，每请求成功一次重新设置redis过期时间
 *      用户在登录后(任何设备)删除之前该用户的在redis中的token(通过存在list类型中的用户名获取到，然后delete(token))，同时更新list类型item的value
 */
public class JwtUtils {

    private static final String SECRET = "colaakadadadadasdasdasdaqweweqweljdasdasdkejakl";        //密钥
//    private static final int InvalidMin = 1;           //失效时间--分钟
    /**
     * 签发JWT
     * @param subject 可以是JSON数据 尽可能少
     */
    public static String createJWT(String id, String subject) {
        Date now = new Date();
//        long expMillis = System.currentTimeMillis() + InvalidMin*60*1000;
//        Date expDate = new Date(expMillis);
        byte[] keyBytes = Decoders.BASE64.decode(SECRET);
        Key key = Keys.hmacShaKeyFor(keyBytes);
        JwtBuilder builder = Jwts.builder()
                .setId(id)
                .setSubject(subject)                            // 主题
//                .setIssuer("colaboot")                          // 签发者
                .setIssuedAt(now)                               // 签发时间
                .signWith(key);    // 签名算法以及密匙
//                .setExpiration(expDate);                      // 过期时间
        return builder.compact();
    }

    /**
     * 从token中获取用户名
     */
    public static String getSubject(String token){
        return getTokenBody(token).getSubject();
    }

    /**
     * 从token中获取ID，同时做解密处理
     */
    public static String getId(String token){
        return getTokenBody(token).getId();
    }
    public static Date getExpDate(String token){
        return getTokenBody(token).getExpiration();
    }

    /**
     * 获取token信息，做校验处理，校验通过后会重新设置过期时间
     */
    private static Claims getTokenBody(String token){
        if(StringUtils.isBlank(token)){
            throw new ColaException("token为空");
        }
        try{
            return Jwts.parserBuilder()
                    .setSigningKey(SECRET).build()
                    .parseClaimsJws(token)
                    .getBody();
        }catch(ExpiredJwtException expired){                                //过期
            throw new ColaException("已过期");
        } catch (Exception e){              //无效
            throw new ColaException("口令无效");
        }
    }

}
